local ROT = require 'rot'
local RNG = ROT.RNG
local FOV_RADIUS = 7
local MAP_SIZE = 40

local Color = require 'game.color'
local System = require 'game.system'
local UI = require 'game.ui'

local Item = require 'game.proto.item'

local state = ROT.Class:extend()

function state:init(game)
    self.game = game
    game.playState = self
    self.fieldbg={ 20, 20, 20 }
end

function state:drawPlayfield()
    local game = self.game
    local scene = game.scene
    local player = game.player
    local display = game.display
    local seen = scene.seen
    local feature = scene.feature
    local radX = 16
    local radY = math.floor((game.display:getHeight() - 8) * 0.5)

    game.display:clear()

    for x = player.x - radX, player.x + radX do
        for y = player.y - radY, player.y + radY do
            local visible = scene.field:getCell(x, y)
            if seen:getCell(x, y) then
                local f = visible and scene:getTile(x, y) or scene:getFeature(x, y)
                local light = visible and ROT.Color.add(
                        scene.ambientLight, scene.light.map:getCell(x, y))
                    or scene.ambientLight

                display:write(f.glyph or ' ',
                    x - player.x + radX + 1,
                    y - player.y + radY + 2,
                    ROT.Color.multiply(light, f.color),
                    visible and self.fieldbg,
                    true)
            end
        end
    end

    -- player

    local light = ROT.Color.add(scene.ambientLight,
        scene.light.map:getCell(player.x, player.y))
    display:write('@', radX + 1, radY + 2,
        ROT.Color.multiply(light, player.color),
        self.fieldbg)

end

function state:update()
    local game = self.game
    local scene = game.scene
    local player = game.player
    local display = game.display
    local seen = scene.seen
    local feature = scene.feature
    local radX = 16
    local radY = math.floor((game.display:getHeight() - 8) * 0.5)

    game.display:clear()

    self:drawPlayfield()

    if scene.name then
        display:write(scene.name, 1, 1, scene.ambientLight)
    end

    local x1 = 35
    local x2 = 45
    local x3 = 55
    local y = 1

    display:write(player.alias .. ' the ' .. player.species .. ' ' .. player.class,
        x1, y, Color.brightYellow)

    -- health

    y = y + 1

    display:write('Health:', x1, y, Color.dark)
    display:write(('%i/%i'):format(math.floor(player.health), player.maxHealth),
        x2, y, Color.brighter)

    local healthOffset = math.max(math.floor(player.health / player.maxHealth * 20), 0)
    local lastHealthOffset = math.max(math.floor(player.lastHealth / player.maxHealth * 20), 0)

    for i = 1, healthOffset do
        display:write('=', x3 + i, y, Color.green)
    end

    if lastHealthOffset > healthOffset then
        for i = healthOffset + 1, lastHealthOffset do
            display:write('-', x3 + i, y, Color.red)
        end
        healthOffset = lastHealthOffset
    elseif lastHealthOffset < healthOffset then
        for i = lastHealthOffset + 1, healthOffset do
            display:write('=', x3 + i, y, Color.darkGreen)
        end
    end
    for i = healthOffset + 1, 20 do
        display:write('-', x3 + i, y, Color.dark)
    end

    player.lastHealth = player.health

    -- stamina

    y = y + 1

    display:write('Stamina:', x1, y, Color.dark)
    display:write(('%i/%i'):format(math.floor(player.stamina), player.maxStamina),
        x2, y, Color.brighter)

    local staminaOffset = math.max(math.floor(player.stamina / player.maxStamina * 20), 0)
    local lastStaminaOffset = math.max(math.floor(player.lastStamina / player.maxStamina * 20), 0)

    for i = 1, staminaOffset do
        display:write('=', x3 + i, y, Color.blue)
    end

    if lastStaminaOffset > staminaOffset then
        for i = staminaOffset + 1, lastStaminaOffset do
            display:write('-', x3 + i, y, Color.purple)
        end
        staminaOffset = lastStaminaOffset
    elseif lastStaminaOffset < staminaOffset then
        for i = lastStaminaOffset + 1, staminaOffset do
            display:write('=', x3 + i, y, Color.darkBlue)
        end
    end
    for i = staminaOffset + 1, 20 do
        display:write('-', x3 + i, y, Color.dark)
    end

    player.lastStamina = player.stamina

    -- stats

    y = y + 1

    display:write('Evade:', x1, y, Color.dark)
    display:write(player.evade, x1 + 7, y, Color.brighter)

    display:write('Armor:', x1, y + 1, Color.dark)
    display:write(0, x1 + 7, y + 1, Color.brighter)

    display:write('Block:', x1, y + 2, Color.dark)
    display:write(0, x1 + 7, y + 2, Color.brighter)


    display:write('STR:', x2, y, Color.dark)
    display:write(player.str, x2 + 5, y, Color.brighter)

    display:write('DEX:', x2, y + 1, Color.dark)
    display:write(player.dex, x2 + 5, y + 1, Color.brighter)

    display:write('INT:', x2, y + 2, Color.dark)
    display:write(player.int, x2 + 5, y + 2, Color.brighter)
    -- gear

    y = y + 3

    display:write('Weapon:', x1, y, Color.dark)
    display:write(player.weapon.name, x2, y, player.weapon.color)

    y = y + 1

    display:write('Armor:', x1, y, Color.dark)
    display:write(player.armor and player.armor.name or 'nothing', x2, y,
        player.armor and player.armor.color or Color.dark)

    -- visible mobs

    y = y + 1

    UI.listTiles(scene.visibleMobs, game.display, x1, y)

    -- key help

    local s = '(? - help)'
    game.display:write(s, game.display:getWidth() - #s, game.display:getHeight())
    local j = 0

    -- message log

    local n = game.prompting and 4 or 6
    local offset = game.prompting and 2 or 0
    for i = #game.messages, #game.messages - n, -1 do
        if i < 1 then break end
        local c = 255 - 32 * j
        local rep = self.game.messageRepeat[i]
        game.display:write(self.game.messages[i]
            .. (rep and (' x' .. tostring(rep)) or ''),
            1, game.display:getHeight()-j-offset, {c, c, c})
        j = j + 1
    end
end

function state:log(msg)
    self.game:log(msg)
    self:update()
    self.game.display:draw()
end

state.command = {}

function state.command.move_nw(state) state.game.scene:movePlayer(-1, -1) end
function state.command.move_n(state) state.game.scene:movePlayer(0, -1) end
function state.command.move_ne(state) state.game.scene:movePlayer(1, -1) end
function state.command.move_w(state) state.game.scene:movePlayer(-1, 0) end
function state.command.move_e(state) state.game.scene:movePlayer(1, 0) end
function state.command.move_sw(state) state.game.scene:movePlayer(-1, 1) end
function state.command.move_s(state) state.game.scene:movePlayer(0, 1) end
function state.command.move_se(state) state.game.scene:movePlayer(1, 1) end

function state.command.interact(state) state.game.scene:interact() end
function state.command.get(state) state.game:pushState('get') end
function state.command.equip(state) state.game:pushState('equip') end
function state.command.map(state) state.game:pushState('map') end
function state.command.examine(state) state.game:pushState('target') end

function state.command.read(state)
    state.game:pushState('consume', {
        title = 'Read scroll',
        type = 'scroll',
    })
end

function state.command.quaff(state)
    state.game:pushState('consume', {
        title = 'Quaff potion',
        type = 'potion',
    })
end

local WAIT_DELAY, WAIT_UPDATE, WAIT_TIME = 5, 25, 100

function state.command.wait(state)
    local n = 0
    local game = state.game
    local scene = game.scene
    local player = game.player

    player.delay = player.delay + WAIT_DELAY
    player.waitTime = WAIT_TIME
end

function state.command.ability(state)
    state.game:pushState('act', {
        title = 'Perform ability',
        type = 'ability',
    })
end

function state.command.eval(state)
    local game = state.game
    local scene = game.scene
    local player = game.player
    local f, e, cmd
    repeat
        f = nil
        if e then state:log(e) end
        cmd = game:prompt('Lua: ',
            'Evaluate Lua. Use `game`, `scene`, `my`/`me`. Blank line aborts.')
        if cmd then
            f, e = load('local game, scene, my, me = ...; ' .. cmd, 'Lua')
            state:log('Lua: ' .. cmd)
        end
        if f then f, e = pcall(f, game, scene, player, player) end
    until not cmd
end

function state:keypressed(key)
    local game = self.game
    local scene = game.scene
    local player = self.game.player
    local command = self.command[game.commandByKey[key]]

    player.command = nil
    if command then
        player.command = game.commandByKey[key]
        scene:passTime() -- only call on keypress
    elseif key==game.keys.scratch then
        game.state = Scratch(game, game.state)
    elseif key=='-' then
        player.alias = game:prompt 'Your new alias: ' or player.alias
    elseif key=='\\' then
        state.game:pushState('world')
    elseif key=='\27' then game.quitting = true
    end

end

return state
